package code1_100.code81_90;

import java.util.ArrayList;
import java.util.List;

/**
 * n 位格雷码序列 是一个由 2n 个整数组成的序列，其中：
 * 每个整数都在范围 [0, 2n - 1] 内（含 0 和 2n - 1）
 * 第一个整数是 0
 * 一个整数在序列中出现 不超过一次
 * 每对 相邻 整数的二进制表示 恰好一位不同 ，且
 * 第一个 和 最后一个 整数的二进制表示 恰好一位不同
 * 给你一个整数 n ，返回任一有效的 n 位格雷码序列 。
 *
 * 输入：n = 2
 * 输出：[0,1,3,2]
 * 解释：
 * [0,1,3,2] 的二进制表示是 [00,01,11,10] 。
 * - 00 和 01 有一位不同
 * - 01 和 11 有一位不同
 * - 11 和 10 有一位不同
 * - 10 和 00 有一位不同
 * [0,2,3,1] 也是一个有效的格雷码序列，其二进制表示是 [00,10,11,01] 。
 * - 00 和 10 有一位不同
 * - 10 和 11 有一位不同
 * - 11 和 01 有一位不同
 * - 01 和 00 有一位不同
 *
 * 输入：n = 1
 * 输出：[0,1]
 */
public class _89grayCode {

    /**
     * 方法1：对称生成
     *
     * 假设我们已经获得n-1位的格雷码序列，只需要将Gn-1对称翻转。
     * 如果我们给反转后的n-1位都加上2^n-1。则新序列和原序列首尾只有一位不同，初始时G0 = {0}
     *
     * 执行用时：     * 7 ms     * , 在所有 Java 提交中击败了     * 66.30%     * 的用户
     * 内存消耗：     * 45.5 MB     * , 在所有 Java 提交中击败了     * 63.68%     * 的用户
     * @param n
     * @return
     */
    public List<Integer> grayCode(int n) {
        List<Integer> ret = new ArrayList<>();
        ret.add(0);
        for (int i = 1; i <= n; i++) {
            int m = ret.size();
            for (int j = m - 1; j >= 0; j--) {
                ret.add(ret.get(j)|(1<<(i-1)));
            }
        }
        return ret;
    }

    /**
     * 方法二：二进制数转格雷码
     *
     * @param n
     * @return
     */
    public List<Integer> grayCode1(int n) {
        List<Integer> ret = new ArrayList<Integer>();
        for (int i = 0; i < 1 << n; i++) {
            ret.add((i >> 1) ^ i);
        }
        return ret;
    }



}
